package internal

import (
	"GameServer/Common/utils"
	"GameServer/Game/dbmodule"
	"GameServer/Game/lib"
	"GameServer/Game/m"
	"sort"
	"sync"
	"time"

	"github.com/globalsign/mgo/bson"
	log "github.com/sirupsen/logrus"
)

// 全局活动信息
type ActivityManager struct {
	Activ *m.JActiv // 记录活动

	grw sync.RWMutex

	MedianSlotLv int64 // 活跃玩家老虎机中位数

	Rich        *m.JGamer // 赢钱最多的玩家
	JackpotRank []*m.JGamer
	rw          sync.RWMutex
}

const jackpotLen int = 100 // 彩金榜长度

func NewActivityManager() *ActivityManager {
	return &ActivityManager{}
}

func (this *ActivityManager) Init() {
	_, activ, err := lib.GetCurrentJackpotActivity()
	if err != nil {
		this.DelActiv()
		return
	}
	// 活动已经开启了
	act := m.GetJActiv(1)
	// 数据库中没有活动，或数据库中的活动id和开启的活动id不一样。
	if act.ActivID == 0 || act.ActivID != int64(activ.ActivId) {
		this.CheckActiv() // 需要重新检测活动信息
		return
	}
	// 数据库中的活动id和配表中的活动id一样
	this.Activ = act
	// 获取jackpot榜
	this.JackpotRank = make([]*m.JGamer, 0)
	err = dbmodule.MgoDB.GameDB.FindAllSortLimit("JGamer", bson.M{"amount": bson.M{"$gt": 0}}, nil, &this.JackpotRank, []string{"-time"}, jackpotLen)
	if err != nil {
		return
	}
	if len(this.JackpotRank) > 0 {
		this.Rich = this.JackpotRank[0]
	}
}

func (this *ActivityManager) Run(closeSig chan bool) {
	for {
		select {
		case <-closeSig:
			return
		case <-time.After(time.Minute):
			this.IncrGoldPerMinute()
		}
	}
}

func (this *ActivityManager) Destroy() {

}

func (this *ActivityManager) CheckActiv() {
	jactiv, activ, err := lib.GetCurrentJackpotActivity()
	if err != nil {
		log.WithFields(log.Fields{
			"err":    err.Error(),
			"method": "ActivityManager.CheckActiv",
		}).Error("jackpot，没有活动，或者配表不能存在")
		this.DelActiv()
		return
	}
	activId := int64(activ.ActivId)
	if this.Activ != nil && activId == this.Activ.ActivID { // 活动运行中
		return
	}

	this.DivGroup()
	jackpotX := lib.GetJackpotX(this.MedianSlotLv)

	beginTime, _ := utils.LayoutToTime(activ.BeginTime)
	endTime, _ := utils.LayoutToTime(activ.EndTime)
	act := &m.JActiv{
		Uid:               1,
		ActivID:           activId,
		GoodLst:           make(map[int64]*m.BaseIdKV),
		GoodNormal:        make(map[int64]*m.BaseIdKV),
		TimeInterval:      make(map[int64]int64),
		Threshold:         make(map[int64]*m.BaseKV),
		IncrGoldSlotScale: make(map[int64]int64),
		IncrGoldPerMinute: make(map[int64]int64),
		BeginTime:         beginTime.Unix(),
		EndTime:           endTime.Unix(),
		JackpotX:          jackpotX,
	}

	for _, item := range jactiv.GoodLst { // 轮盘道具
		act.GoodLst[int64(item.Id)] = &m.BaseIdKV{Id: int64(item.Id), Key: int64(item.Key), Val: int64(item.Value)}
	}
	for _, item := range jactiv.TimeInterval { // 派奖时间间隔
		act.TimeInterval[int64(item.Key)] = int64(item.Value)
	}
	for _, item := range jactiv.Threshold { // 基础奖金和派发奖金
		act.Threshold[int64(item.Id)] = &m.BaseKV{Key: int64(item.Key) * jackpotX, Val: int64(item.Value) * jackpotX}
	}
	for _, item := range jactiv.IncrGoldSlotScale { // 老虎机总产出金币比例
		act.IncrGoldSlotScale[int64(item.Key)] = int64(item.Value)
	}
	for _, item := range jactiv.IncrGoldPerMinute { // 每分钟增加金币
		act.IncrGoldPerMinute[int64(item.Key)] = int64(item.Value) * jackpotX
	}

	nowUnix := utils.TNow().Unix()
	group := m.GetJGroup(1)
	for _, item := range jactiv.GoodLst {
		goodTid := int64(item.Key) // 道具tid
		plate := int64(item.Id)    // 轮盘id

		if val, ok := act.Threshold[goodTid]; ok { //给组添加大奖
			group.MBonus[goodTid] = &m.JBonus{
				BonusId: goodTid,
				Plate:   plate,
				Amount:  val.Key,
				Time:    nowUnix,
			}
		} else { // 普通道具
			act.GoodNormal[plate] = &m.BaseIdKV{Id: plate, Key: goodTid, Val: int64(item.Value)}
		}
	}
	group.Update(group)

	act.Update(act)
	this.Activ = act
}

func (this *ActivityManager) DivGroup() {
	uLst := make([]*m.User, 0)
	err := dbmodule.MgoDB.GameDB.FindAll("user", bson.M{"slotLv": bson.M{"$gt": 1}}, nil, &uLst)
	if err != nil {
		log.WithFields(log.Fields{
			"err":    err,
			"method": "ActivityManager.CheckActiv",
		}).Error("jackpot彩金大奖获取用户失败")
		return
	}

	sort.Slice(uLst, func(i, j int) bool {
		return uLst[i].SlotLv > uLst[j].SlotLv
	})

	length := len(uLst)
	if length&1 == 1 {
		this.MedianSlotLv = uLst[length/2].SlotLv
	} else {
		this.MedianSlotLv = (uLst[length/2].SlotLv + uLst[length/2-1].SlotLv) / 2
	}

	uLst = make([]*m.User, 0)
	err = dbmodule.MgoDB.GameDB.FindAll("user", nil, nil, &uLst)
	if err != nil {
		log.WithFields(log.Fields{
			"err":    err,
			"method": "ActivityManager.CheckActiv",
		}).Error("jackpot彩金大奖获取用户失败")
		return
	}

	for _, item := range uLst {
		gamer := &m.JGamer{
			Uid:         item.Uid,
			Name:        item.Name,
			Head:        item.Head,
			AvatarFrame: item.AvatarFrame,
		}
		gamer.Update(gamer)
	}
}

// 大奖每分钟增加金额
func (this *ActivityManager) IncrGoldPerMinute() {
	if this.Activ == nil || this.Activ.ActivID == 0 {
		return
	}
	jr := m.GetJGroup(1)
	jr.AddBonus(this.Activ.IncrGoldPerMinute, this.Activ.TimeInterval, this.Activ.Threshold)

}

// 大奖每消耗体力增加金额
func (this *ActivityManager) IncrGoldSlotScale(gold int64) {
	if this.Activ == nil || this.Activ.ActivID == 0 {
		return
	}
	incrGold := make(map[int64]int64)
	for key, val := range this.Activ.IncrGoldSlotScale {
		incrGold[key] = val * gold / 10000
	}
	jr := m.GetJGroup(1)
	jr.AddBonus(incrGold, this.Activ.TimeInterval, this.Activ.Threshold)
}

// 是否有活动
func (this *ActivityManager) HasActive() bool {
	return this.Activ != nil && this.Activ.ActivID != 0
}

// 记录玩家获取的大奖
func (this *ActivityManager) JackpotGamerList(u *m.User, amount, jtype, jtime int64) {
	jg := m.GetJGamer(u.Uid.Hex())
	jg.Uid = u.Uid
	jg.Name = u.Name
	jg.Head = u.Head
	jg.AvatarFrame = u.AvatarFrame
	jg.Jtype = jtype
	jg.Amount = amount
	jg.Time = jtime
	jg.Update(jg)
	this.rw.Lock()
	defer this.rw.Unlock()
	jr := &m.JGamer{
		Uid:         u.Uid,
		Name:        u.Name,
		Head:        u.Head,
		AvatarFrame: u.AvatarFrame,
		Jtype:       jtype,
		Amount:      amount,
		Time:        jtime,
	}

	if this.Rich == nil || this.Rich.Amount < jr.Amount {
		this.Rich = jr
	}

	jrLst := make([]*m.JGamer, 0)
	for _, item := range this.JackpotRank {
		if item.Uid == u.Uid {
			continue
		}
		jrLst = append(jrLst, item)
	}

	this.JackpotRank = make([]*m.JGamer, 0)
	this.JackpotRank = append(this.JackpotRank, jr)
	lenght := len(jrLst)
	if lenght == jackpotLen {
		lenght--
	}
	this.JackpotRank = append(this.JackpotRank, jrLst[:lenght]...)
	return
}

// 获取jackpot榜
func (this *ActivityManager) GetJackpotRank() (r []*m.JGamer, rich *m.JGamer) {
	this.rw.RLock()
	defer this.rw.RUnlock()

	r = make([]*m.JGamer, 0)
	for _, item := range this.JackpotRank {
		r = append(r, item)
	}
	rich = this.Rich
	return
}

func (this *ActivityManager) DelActiv() {
	activ := &m.JActiv{Uid: 1}
	activ.Update(activ)
	this.Activ = activ
}
